package sunyu.tools.redis;

import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;

import javax.annotation.Resource;
import java.util.Map;
import java.util.TreeSet;

@Component
public class JedisTools {

    private static final Logger logger = LoggerFactory.getLogger(Thread.currentThread().getClass());

    @Resource(name = "jedisPool")
    private JedisPool jedisPool;

    @Resource(name = "jedisCluster")
    private JedisCluster jedisCluster;//内部已经实现了连接池

    private Mirror<?> mirror = Mirror.me(JedisCluster.class);//反射镜像

    public Jedis getJedis() {
        return jedisPool.getResource();
    }

    public JedisCluster getJedisCluster() {
        return jedisCluster;
    }

    public <T> T execute(JedisCallback<T> action) {
        logger.debug("从jedisPool中获取jedis");
        Jedis jedis = getJedis();
        try {
            logger.debug("执行回调");
            return action.doInJedis(jedis);
        } catch (Throwable throwable) {
            throw Lang.wrapThrow(throwable);
        } finally {
            logger.debug("放回连接池");
            jedis.close();
        }
    }

    public <T> T clusterExecute(JedisClusterCallback<T> action) {
        logger.debug("从集群中获取jedis");
        JedisCluster jedis = getJedisCluster();
        try {
            logger.debug("执行回调");
            return action.doInJedisCluster(jedis);
        } catch (Throwable throwable) {
            throw Lang.wrapThrow(throwable);
        }
    }

    public <T> T clusterExecute(String methodName,
                                Object... args) {
        if (methodName.equals("keys")) {
            return (T) clusterKeys(args[0].toString());
        } else {
            return (T) mirror.invoke(jedisCluster, methodName, args);
        }
    }

    /**
     * 由于JedisCluster没有实现keys操作，这里自己实现以下
     *
     * @param pattern
     *
     * @return
     */
    public TreeSet<String> clusterKeys(String pattern) {
        TreeSet<String> keys = new TreeSet<>();
        Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
        for (String k : clusterNodes.keySet()) {
            JedisPool jp = clusterNodes.get(k);
            Jedis connection = jp.getResource();
            try {
                keys.addAll(connection.keys(pattern));
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                connection.close();
            }
        }
        return keys;
    }

}